package eai.tp1.core;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

import eai.tp1.core.datamodel.Date;
import eai.tp1.core.datamodel.DigitalCamera;
import eai.tp1.core.source.IWebPageSource;
import java.util.Arrays;
import java.util.Arrays;

/**
 * This class consist of a screen scraping engine, that connects to a web page
 * source and processes it to extract the data.
 * 
 * @author Joel
 * 
 */
public class SSEngine {

    /**
     * This method receives as input a web page source and a brand and outputs a
     * digital camera list.
     *
     * @param webSource
     * @param brand
     * @return
     * @throws IOException
     */
    public List<DigitalCamera> extract(IWebPageSource webSource, String brand)
            throws IOException {
        List<DigitalCamera> list = new ArrayList<DigitalCamera>();
        String line;
        String page;
        BufferedReader br;
        // connection to the web page
        URL url;
        URLConnection connection;
        url = new URL(webSource.getBrandLink(brand));
        connection = url.openConnection();
        connection.setRequestProperty("User-Agent", "");
        // Save the page in memory
        br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        // Printout the resulting page
        line = null;
        page = "";
        do {
            line = br.readLine();
            page += line;
        } while (line != null);
        br.close();
        // Extract a list of links to each camera of that brand
        List<URL> urls = getDigitalCameraURLS(webSource, page);
        // For each link, extract the data required for a digital camera
        for (URL cameraURL : urls) {
            connection = cameraURL.openConnection();
            connection.setRequestProperty("User-Agent", "");
            br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            line = null;
            page = "";
            do {
                line = br.readLine();
                page += line;
            } while (line != null);
            br.close();
            list.add(getDigitalCamera(webSource, page, brand));
        }        
        return list;
    }

    /**
     * This method returns a list of urls to all the cameras of the brand
     *
     * @param webSource
     * @param br
     * @return
     * @throws IOException
     */
    private List<URL> getDigitalCameraURLS(IWebPageSource webSource,
            String website) throws IOException {
        List<URL> urls = new ArrayList<URL>();
        Matcher match = webSource.getDigitalCameraList().matcher(website);
        int startPos = 0;
        while (match.find(startPos)) {
            String link = match.group(1);
            urls.add(new URL(webSource.getRootLink() + link));
            startPos = match.end();
        }
        return urls;
    }

    /**
     * This method creates a class representing a digital camera, with the data
     * extract from the web page source
     *
     * @param webSource
     * @return
     */
    private DigitalCamera getDigitalCamera(IWebPageSource webSource,
            String website, String brand) {
        DigitalCamera digCam = new DigitalCamera();
        digCam.setBrand(brand);
        digCam.setId(id++);

        // Name
        Matcher match = webSource.getName().matcher(website);
        int startPos = 0;
        while (match.find(startPos)) {
            String name = match.group(1);
            digCam.setName(name);
            startPos = match.end();
        }

        // Min Shutter
        match = webSource.getMinShutter().matcher(website);
        digCam.setMinShutter(matcher(match, 1));

        // Image Ratio
        match = webSource.getImageRatio().matcher(website);
        digCam.setImageRatio(matcher(match, 1));

        // ISO Rating
        match = webSource.getIsoRating().matcher(website);
        digCam.setIsoRating(matcher(match, 1));

        // Sensor Size
        match = webSource.getSensorSize().matcher(website);
        String tmp = matcher(match, 1) + matcher(match, 2); // needs to merge 2
        // groups of strings
        tmp = tmp.replace("&sup2;", "2"); // puts the square after the cm
        digCam.setSensorSize(tmp);

        // Date
        match = webSource.getDate().matcher(website);
        digCam.setDate(new Date(matcher(match, 1)));

        // Effective Pixels
        match = webSource.getEffectivePixels().matcher(website);
        digCam.setEffectivePixels(matcher(match, 1));

        // Image Link
        match = webSource.getImageLink().matcher(website);
        digCam.setImageLink(matcher(match, 1));

        // Max Resolution
        match = webSource.getMaxRes().matcher(website);
        digCam.setMaxRes(getMaxResolution(matcher(match, 1)));

        // Min Resolution
        match = webSource.getMinRes().matcher(website);
        digCam.setMinRes(getMinResolution(matcher(match, 1)));

        // Max shutter
        match = webSource.getMaxShutter().matcher(website);
        digCam.setMaxShutter(matcher(match, 1));

        // Min shutter
        match = webSource.getMinShutter().matcher(website);
        digCam.setMinShutter(matcher(match, 1));

        // Review Link
        match = webSource.getReviewLink().matcher(website);
        tmp = matcher(match, 1);
        if (tmp != null) {
            digCam.setReviewLink("www.dpreview.com/reviews/" + matcher(match, 1));
        }

        // Description
        match = webSource.getDescription().matcher(website);
        digCam.setDescription(matcher(match, 1));

        return digCam;
    }

    // This method matches the expression to the string and returns the string
    private String matcher(Matcher match, int group) {
        String alfa = null;

        if (match.find(0)) {
            alfa = match.group(group);
        }

        try {
            match.end();
        } catch (Exception e) {
            alfa = null;
        }
        return alfa;
    }
    private int id = 1;

    private String getMinResolution(String matcher) {

        String[] resolutions = matcher.split("\\s*,\\s*");
        String stringMinRes = "";
        Integer n = Integer.MAX_VALUE;

      
        for (int i = 0; i < resolutions.length; i++) {
            stringMinRes = verifyLowerRes(resolutions[i].trim(), n, stringMinRes);

        }

        return stringMinRes;
    }

    private String getMaxResolution(String matcher) {

        String[] resolutions = matcher.split("\\s*,\\s*");
        String stringMaxRes = "";
        Integer n = 0;

        
        for (int i = 0; i < resolutions.length; i++) {
           stringMaxRes = verifyGreaterRes(resolutions[i].trim(), n, stringMaxRes);

        }

        
        return stringMaxRes;
    }

    private String verifyLowerRes(String cameraResolution, Integer minRes, String stringMinRes) {

        String[] nums = cameraResolution.split("\\s*x\\s*");
        try {

            //So verifica se o padrao estiver correcto
            if (nums.length == 2) {
                if (minRes > (Integer.parseInt(nums[0]) * Integer.parseInt(nums[1]))) {
                    minRes = Integer.parseInt(nums[0]) * Integer.parseInt(nums[1]);
                    stringMinRes = cameraResolution;
                }

            }
           return stringMinRes;

        } catch (NumberFormatException nfe) {
           // nfe.printStackTrace();
        }
        return "";
    }

    private String verifyGreaterRes(String cameraResolution, Integer maxRes, String stringMaxRes) {

        String[] nums = cameraResolution.split("\\s*x\\s*");
        try {

            //So verifica se o padrao estiver correcto
            if (nums.length == 2) {
                if (maxRes < (Integer.parseInt(nums[0]) * Integer.parseInt(nums[1]))) {
                    maxRes = Integer.parseInt(nums[0]) * Integer.parseInt(nums[1]);
                    stringMaxRes = cameraResolution;
                }

            }

        return stringMaxRes;
        } catch (NumberFormatException nfe) {
           // nfe.printStackTrace();
        }
        return "";
    }
}
